package art.yulang.factory;


import art.yulang.annotation.*;
import org.reflections.Reflections;

import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Field;
import java.util.*;

public class AnnotationBeanFactory {
    private static Map<String, Object> map = new HashMap<String, Object>();

    /**
     * 任务一：使用第三方工具Reflections扫面指定包下的所有带@Component、@Repository、@Service 注解的类，通过反射技术实例化对象并且存储待用（map集合）
     */
    static  {
        //要扫描的包名
        Reflections f = new Reflections("art.yulang");

        Set<Class<?>> componentSet = f.getTypesAnnotatedWith(Component.class);
        Set<Class<?>> repositorySet = f.getTypesAnnotatedWith(Repository.class);
        Set<Class<?>> serviceSet = f.getTypesAnnotatedWith(Service.class);

        try {
            //普通bean
            for (Class<?> aClass : componentSet) {
                Object o = null;
                o = aClass.newInstance();
                Component annotation = o.getClass().getAnnotation(Component.class);
                String id = annotation.value();
                if(null == id || "".equals(id)){
                    String className = o.getClass().getSimpleName();// 获取类名
                    String big = className.substring(0, 1);// 获取首字母（类名首字母大写）
                    String small = big.toLowerCase();// 将首字母变为小写
                    id = small + className.substring(1);// 获得已小写字母开头的类名
                }
                map.put(id, o);
            }

            //dao层bean
            for (Class<?> aClass : repositorySet) {
                Object o = null;
                o = aClass.newInstance();
                Repository annotation = o.getClass().getAnnotation(Repository.class);
                String id = annotation.value();
                if(null == id || "".equals(id)){
                    String className = o.getClass().getSimpleName();// 获取类名
                    String big = className.substring(0, 1);// 获取首字母（类名首字母大写）
                    String small = big.toLowerCase();// 将首字母变为小写
                    id = small + className.substring(1);// 获得已小写字母开头的类名
                }
                map.put(id, o);
            }

            //service层bean
            for (Class<?> aClass : serviceSet) {
                Object o = null;
                o = aClass.newInstance();
                Service annotation = o.getClass().getAnnotation(Service.class);
                String id = annotation.value();
                if(null == id || "".equals(id)){
                    String className = o.getClass().getSimpleName();// 获取类名
                    String big = className.substring(0, 1);// 获取首字母（类名首字母大写）
                    String small = big.toLowerCase();// 将首字母变为小写
                    id = small + className.substring(1);// 获得已小写字母开头的类名
                }
                map.put(id, o);
            }

            /**
             * 1、循环迭代已注册bean，判断bean的属性中是否有带@Autowired注解的属性，有则以byName的形式进行注入
             * 2、对于有@Transactional注解的bean生成其代理对象并返回覆盖map中的值
             */
            Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
            while (iterator.hasNext()){
                Map.Entry<String, Object> next = iterator.next();
                String key = next.getKey();
                Object value = next.getValue();
                Field[] fields = value.getClass().getDeclaredFields();
                for (Field field : fields) {
                    boolean present = field.isAnnotationPresent(Autowired.class);
                    if(present){
                        field.setAccessible(true);
                        field.set(value,map.get(field.getName()));//byName注入暂未考虑byType注入
                        field.setAccessible(false);
                    }
                }

                /**
                 * 根据bean的getInterfaces().length 判定bean是否实现了接口，当实现了接口是调用JDK动态代理生成代理对象
                 * 否则使用Cglib生成代理对象
                 */
                boolean present = value.getClass().isAnnotationPresent(Transactional.class);
                Class<?>[] interfaces = value.getClass().getInterfaces();
                boolean isImplObj = interfaces.length > 0 ? true : false;
                if(present){
                    ProxyFactory proxyFactory = (ProxyFactory) map.get("proxyFactory");
                    value = isImplObj ? proxyFactory.getJDKProxyObject(value) : proxyFactory.getCglibProxyObject(value);
                }
                map.put(key, value);
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 任务二：对外提供获取实例对象的接口（根据id获取）
     * @param id
     * @return
     */
    public static Object getBean(String id){
        return map.get(id);
    }
}
